package com.du.fileload.framework.utils;

import com.du.fileload.framework.config.JWTConfig;
import com.du.fileload.framework.config.JWTypeEnum;
import com.google.gson.Gson;
import io.jsonwebtoken.*;
import io.jsonwebtoken.gson.io.GsonDeserializer;
import io.jsonwebtoken.gson.io.GsonSerializer;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtUtil {



    /**
     * 生成token
     *
     * @param claims 要传送消息map
     * @return
     */
    public static String generate(Map<String, Object> claims) {
        Date nowDate = new Date();
        //过期时间,设定为一分钟
        Date expireDate = new Date(System.currentTimeMillis() + JWTConfig.getInstance().getExpiration());
        //头部信息,可有可无
        Map<String, Object> header = new HashMap<>(2);
        header.put("jtype", JWTypeEnum.auth);
        //更强的密钥,JDK11起才能用
        //  KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256);
        //  PrivateKey key1 =  keyPair.getPrivate();  // 私钥
        //PublicKey key2 =  keyPair.getPublic();  //公钥

        return Jwts.builder().serializeToJsonWith(new GsonSerializer<>(new Gson())).setHeader(header)
                // .setSubject("weimi")//主题
                // .setIssuer("weimi") //发送方
                .setClaims(claims)  //自定义claims
                .setIssuedAt(nowDate)//当前时间
                .setExpiration(expireDate) //过期时间
                .signWith(JWTConfig.getInstance().getKey())//签名算法和key
                .compact();
    }

    /**
     * 生成token
     *
     * @param header 传入头部信息map
     * @param claims 要传送消息map
     * @return
     */
    public static String generate(Map<String, Object> header, Map<String, Object> claims) {
        Date nowDate = new Date();
        //过期时间,设定为一分钟
        Date expireDate = new Date(System.currentTimeMillis() + JWTConfig.getInstance().getExpiration());
        header.put("jtype", JWTypeEnum.auth);
        return Jwts.builder().serializeToJsonWith(new GsonSerializer<>(new Gson())).setHeader(header)
                // .setSubject("weimi")//主题
                //    .setIssuer("weimi") //发送方
                .setClaims(claims)  //自定义claims
                .setIssuedAt(nowDate)//当前时间
                .setExpiration(expireDate) //过期时间
                .signWith(JWTConfig.getInstance().getKey())//签名算法和key
                .compact();
    }

    /**
     * 校验签名是否正确
     *
     * @param token
     * @return
     */
    public static boolean verify(String token) {
        boolean result= false;
        try {
            Jwts.parserBuilder()
                    .setSigningKey(JWTConfig.getInstance().getKey())
                    .build()
                    .parseClaimsJws(token);
            result=true;
        }catch (JwtException e){
            result=false;
        }finally {
            return result;
        }
    }

    /**
     * 获取header中的数据
     * @param jwsString
     * @return
     */
    public static Map<String,Object> getHeader(String jwsString){
        return parseJwtResultJws(jwsString).getHeader();
    }

    /**
     * 获取PayLoad中携带的数据
     * @param jwsString
     * @return
     */
    public static Map<String,Object> getPayLoad(String jwsString){
        return ((Map<String, Object>) (parseJwtResultJws(jwsString)).getBody());
    }

    /**
     * 获取除去exp和iat的数据，exp：过期时间，iat：JWT生成的时间
     * @param jwsString
     * @return
     */
    public static Map<String,Object> getPayLoadALSOExcludeExpAndIat(String jwsString){
        Map<String, Object> map = getPayLoad(jwsString);
        map.remove("exp");
        map.remove("iat");
        return map;
    }


    /**
     * 校验令牌
     * @return       java.lang.Boolean
     */
    public static Boolean validateToken(String token) {
        Jws<Claims> claimsFromToken = parseJwtResultJws(token);
        return (null!=claimsFromToken && !isTokenExpired(token));
    }

    /**
     * 验证token 是否过期
     * @return       java.lang.Boolean
     */
    public static Boolean isTokenExpired(String token) {
        try {
            Jws<Claims> claims = parseJwtResultJws(token);
            Date expiration =claims.getBody().getExpiration();
            return expiration.before(new Date());
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * 刷新token
     * @return       java.lang.String
     */
    public static String refreshToken(String refreshToken,Map<String, Object> claims) {
        String refreshedToken;
        try {
            Jws<Claims> parserclaims = parseJwtResultJws(refreshToken);
            /**
             * 刷新token的时候如果为空说明原先的 用户信息不变 所以就引用上个token里的内容
             */
            if(null==claims){
                claims= (Map<String, Object>) (parserclaims.getBody());
            }
            refreshedToken = generate(getHeader(refreshToken),claims);
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }

    /**
     * 获取jwt发布时间
     */
    public static Date getIssuedAt(String token) {
        return parseJwtResultJws(token).getBody().getIssuedAt();
    }

    /**
     * 获取jwt失效时间
     */
    public static Date getExpiration(String token) {
        return parseJwtResultJws(token).getBody().getExpiration();
    }

    /**
     * 验证token是否失效
     *
     * @param token
     * @return true:过期   false:没过期
     */
    public static boolean isExpired(String token) {
        try {
            final Date expiration = getExpiration(token);
            return expiration.before(new Date());
        } catch (ExpiredJwtException expiredJwtException) {
            return true;
        }
    }

    /**
     * 获取token的剩余过期时间
     * @return       long 毫秒
     */
    public static long getRemainingTime(String token){
        long result=0;
        try {
            long nowMillis = System.currentTimeMillis();
            result= parseJwtResultJws(token).getBody().getExpiration().getTime()-nowMillis;
        } catch (Exception e) {
        }
        return result;
    }

    /**
     * 解析Jws,返回一个Jws对象
     * @param token
     * @return
     */
    public static Jws<Claims> parseJwtResultJws(String token){
        Jws<Claims> claims=null;
        try {
            claims = Jwts.parserBuilder().deserializeJsonWith(new GsonDeserializer<>(new Gson()))
                    .setSigningKey(JWTConfig.getInstance().getKey())
                    .build()
                    .parseClaimsJws(token);
        }catch (JwtException e){
            e.printStackTrace();
        }
        return claims;
    }
}
